#ifndef _MATH_EXPRESSION_SHANFL_H
#define _MATH_EXPRESSION_SHANFL_H
#include <map>
#include <string>
#include <vector>
#include <deque>
#include <iostream>

/*
    // demo1
    MathExpr::MathExpression math2;
    math2.add_var("x1", 1);
    math2.add_var("x2", 2);
    math2.add_var("x3", 1);
    math2.add_var("x4", 2);
    math2.add_var("x5", 1);
    math2.add_var("x6", 2);
    math2.add_var("y1", 1);
    math2.add_var("y2", 2);
    math2.add_var("y3", 1);
    math2.add_var("y4", 2);
    math2.add_var("y5", 1);
    math2.add_var("y6", 2);
    double v =
   math2.eval("3.1415926/6*sqrt((x1-x2)^2+(y1-y2)^2)*sqrt((x3-x4)^2+(y3-y4)^2)*sqrt((x5-x6)^2+(y5-y6)^2)").second;
*/

namespace MathExpr {
static const double E = 2.718281828459045;

enum TType
{
    NONE,
    NAME,
    SEP,
    OP,
    NUMBER,
};

struct Token
{
    std::string str;
    double value = 0;
    TType type;
    int needParamNum = 1; // 例如 max()函数支持任意多个参数

    Token(TType t, char c)
    {
        str  = c;
        type = t;

        if (t == NUMBER)
        {
            if (c == 'E')
            {
                value = E;
            }
            else
            {
                value = atof(str.c_str());
            }
        }
    }

    Token(TType t, std::string c)
    {
        str  = c;
        type = t;

        if (t == NUMBER)
        {
            if (str[str.length() - 1] == 'E')
            {
                if (str == "-E")
                {
                    value = -E;
                }
                else
                {
                    value = E * atof(str.substr(0, str.length() - 1).c_str());
                }

                // TODO:
                // -.E   --- > 这是不对的,目前辨别成本较高.
            }
            else
            {
                value = atof(str.c_str());
            }
        }
    }

    Token(double d)
    {
        str   = "";
        value = d;
        type  = NUMBER;
    }

    bool IsOp()
    {
        return type == OP;
    }

    bool IsOP_POWER()
    {
        return IsOp() && str == "^";
    }
};

using FN1 = double (*)(double);
using FN2 = double (*)(std::vector<double> params);

class MathExpression
{
public:
    MathExpression(std::map<std::string, double> otherItems = {});
    void add_fn1(std::string name, FN2 fn);
    std::pair<bool, double> eval(std::string mathexpr_str);
    void clear_var();

    void add_var(std::string varname, double value);

    void RPN_Print();

protected:
    bool Parser(std::string str);
    // 单纯的 - 负号转为 -1 *
    void handleMinus();
    bool InfixToRPN();
    bool IsZeroFloat(float f);
    bool RPNToDouble(double& v);

    // --
    inline int precedence(const Token& o)
    {
        if (o.str == "+" || o.str == "-")
            return 1;
        else if (o.str == "*" || o.str == "/")
            return 2;
        else if (o.str == "^")
            return 3;
        else if (IsFunction(o))
            return 999;
        else
            return 4;
    }

    bool IsFunction(Token& tk);
    bool IsFunction(const Token& tk);
    bool IsVariable(Token& tk);
    bool IsOp(Token& tk);
    bool IsNumber(Token& tk);

private:
    std::map<std::string, double> m_vars;
    std::vector<Token> m_tokens;

    std::deque<Token> m_OperatorStack;
    std::deque<Token> m_RPN;
    // std::map<std::string, FN1> m_FN1_map;
    std::map<std::string, FN2> m_FN1_map;
};
} // namespace MathExpr

#endif // PARSERMATH_H
